Progetto DSIM - Face recognition


Autori: Ginevra Mariani | Lorenzo Mora | Confalonieri Riccardo
E-mail: g.mariani34@campus.unimib.it | l.mora4@campus.unimib.it | r.confalonieri5@campus.unimib.it

L'obiettivo di questo notebook è creare un classificatore che riconosca i volti dei $3$ componenti del gruppo. A tale scopo verranno provati approcci di fine tuning con pesi addestrati sul task imagenet e una rete preaddestrata su un task di riconoscimento dei volti.
Per quanto concerne le immagini date in input ai modelli si utilizzeranno dei crop, preventivamente ottenuti, contenenti il solo volto della persona.

Import packages

Image cropping

Per poter addestrare i modelli è necessario ritagliare le immagini a disposizione estraendo il riquadro contenente il solo volto della persona. Per farlo si sono utilizzati dei face detector ad hoc, e sono state considerate due implementazioni:

Si sono testati entrambi i face detector, i cui metodi di estrazione sono presenti nelle due sezioni successive per chiarezza, ma alla fine i volti sono stati estratti usando dlib che ha permesso di croppare con successo tutte le immagini a disposizione!

NOTA: Una volta ottenuti i crop si è proceduto a mano a creare i relativi .zip, e nel caso delle immagini di training/validation si è proceduto con una separazione manuale in due sottocartelle. Tuttavia si poteva anche procedere con una suddivisione automatica via codice!

NOTA2: Dato che gli .zip sono salvati su drive questo codice non va eseguito, è stato lasciato solo per completezza!

Face detector: OpenCV

La prima opzione considerata per effettuare i crop delle immagini è stata quella di utilizzare il face detector fornito da OpenCV.

Come si può notare già per le immagini di training e validation molte non sono croppate con successo! Quindi si è passatti al face detector di dlib.

Face detector: dlib

Per l'implementazione del codice ci si è basati alla documentazione della libreria presente al seguente link.

L'aspetto negativo di questo face detector è che richiede una GPU, in Colab non vi sono tuttavia problemi con la sua esecuzione.

Come si può notare dagli output l'esecuzione non ha dato errori, e per tutte le immagini è stato trovato un crop valido.

Data Loader

Per velocizzare il caricamento le immagini necessarie sono già state preventivamente salvate in formato .zip e suddivise in sottocartelle, ognuna contenente una specifica classe (i.e. persona). In questo modo è possibile utilizzare i metodi di import di keras che velocizzano ed ottimizzano il caricamento. Inoltre le immagini sono state divise preventivamente in training, validation e test set. Infine avendo creato manualmente le immagini si è certi che le classi siano bilanciate, questo supponendo che nel caso reale tutti e $3$ i componenti siano presenti nell'immagine altrimenti avrebbe più senso creare un test set sbilanciato a favore della persona maggiormente presente per verificare la bontà del modello.

Il dataset caricato è di tipo proprietario di keras, inoltre possiamo notare che i valori presenti nell'immagine sono di tipo float e che le immagini sono state ridimensionate alla shape richiesta durante l'import.

Visual inspection

Proviamo a visualizzare qualche immagine per capirne le caratteristiche.

È possibile notare come nelle immagini contengono solo il soggetto da classificare, tuttavia ci sono variazioni di luce ed espressione tra le diverse immagini. In alcuni casi sono presenti anche le mani dei soggetti.

Funzioni utili

Si definiscono alcune funzioni utili, comuni a tutti i modelli che verranno implementati. In questo modo è possibile visualizzare l'andamento del training con il confronto di loss e accuracy sul training e validation set ed anche effettuare le predizioni su un test set visualizzando i risultati in maniera grafica.

VGG-16

Il primo modello che andiamo ad analizzare è VGG16. Questo modello è caratterizzata dall'applicazione di una serie di blocchi convoluzionali con dimensioni del kernel piccole, seguiti poi da due diversi layer fully connected che mappano a $4096$ e un ultimo layer finale che mappa a $1000$, la dimensione del problema di classificazione originale. Questi ultimi layer in particolare richiedono un numero molto alto di parametri e anche rispetto al numero di operazioni richieste questa rete risulta essere molto complessa rispetto ad altre possibile scelte che verranno analizzate successivamente.

VGG16 architecture


Come si può notare dall'immagine la prima operazione richiesta per utilizzare questa architettura e utilizzare delle immagini con dimensione $224x244$ quindi sarà necessario riscalare opportunamente la dimensione dei crop ottenuti dalle immagini durante l'import.

Una volta estratti i layer funzionali al nostro task definisco un nuovo modello che aggiunge dei nuovi layer utili per la classificazione. I layer estratti dal modello vgg16 verranno ''bloccati'' durante il training della nuova rete in modo da non modificare i pesi precedentemente allenati.

Si può verificare che il modello VGG così creato contiene $15.518.115$ di cui $803.427$ trainabili. Il modello risulta quindi essere molto grande, questo ci aspettiamo che risulti in un maggiore tempo necessario per il training.

Inoltre si segnala che l'architettura finale, intesa sia come numero di layer che come parametri, è stata individuata a seguito di alcune prove effettuate in cui è risultata essere la migliore.

Effettuiamo il training del modello con un numero massimo di $100$ epoche, inoltre con la tecnica dell'EarlyStopping il modello verrà interrotto qualora per tre epoche consecutive non vi fossero miglioramenti nella validation loss. Nel caso in cui il training fosse interrotto verranno anche ripristinati i pesi migliori individuati precedentemente, cosi da poter ottenere il miglior risultato.

Si visualizza quindi il grafico di training, le epoche rimosse per via dell'early stopping sono mostrate con linee tratteggiate.

Come si può notare dal grafico, e dai valori riportati, il modello ottiene una buona accuracy e anche l'andamento sembra essere buono.

Valutiamo quindi il modello sul test set precedentemente caricato.

Come previsto i risultati sono in linea con quelli del validation, è possibile notare come in generale il modello sia molto nel prevedere tutte e $3$ le classi. Tuttavia la classe riportante le immagini di 'Lorenzo' risulta essere lievemente peggiore con una recall di $0.82$.
Proviamo inoltre a valutare il modello rispetto al tempo richiesto per predire una sola immagine, per farlo si effettua la predizione su un batch di immagini e si media il tempo totale. Ovviamente la tempistica è inficiata dalla potenza di calcolo e dal numero di GPU a disposizione (exe parallela).

Il tempo per la previsione risulta essere abbastanza elevato, complice anche la grandezza del modello. Questo può essere un fattore negativo in quanto non permette predizioni real-time.

MobileNetV2

Il secondo modello che consideriamo per il fine tuning è MobileNetV2. Questo modello ha un numero di parametri inferiore al precedente e richiede un numero minimo di operazioni, quindi anche il peso del modello è molto leggero: solo $14$MB. Nonostante questo sul task originale riesce a raggiungere gli stessi livelli di accuratezza di VGG16! Questo modello è stato infatti sviluppato da Google per essere utilizzato su dispositivi mobili.
L'architettura di MobileNetV2 si basa su dei blocchi detti:

L'architettura completa è quindi composta dai seguenti layers:

MobileNetV2 architecture

Dove $t$ è il fattore di espansione, $c$ il numero di canali in output, $n$ il numero di ripetizioni, $s$ lo stride. Per le convoluzioni spaziali è utilizzato un kernel $3x3$.

Si è scelto di provare a utilizzare questo modello in quanto, se efficace, potrebbe rendere possibile il riconoscimento in real-time sfruttando le immagini che arrivano in modo continuo da un video.

Una volta estratti i layer funzionali al nostro task definisco un nuovo modello che aggiunge dei nuovi layer utili per la classificazione. I layer estratti dal modello MobileNetV2 verranno ''bloccati'' durante il training della nuova rete in modo da non modificare i pesi precedentemente allenati.

Come prima l'architettura finale è stata individuata dopo alcune prove.

Si può verificare che il modello così creato contiene $2.261.827$ di cui $3.843$ trainabili. Il modello risulta quindi essere molto più piccolo del precedente e con molti pochi parametri da trainare.

Effettuiamo il training del modello con la stessa configurazione precedente, ovvero $100$ epoche massime ed EarlyStopping.

Si visualizza quindi il grafico di training, le epoche rimosse per via dell'early stopping sono mostrate con linee tratteggiate.

Come si può notare dal grafico, e dai valori riportati, il modello ottiene una buona accuracy. Dal punto di vista dell'andamento invece sembra leggermente essere in overfitting se ci concentriamo sulla metrica di loss.

Valutiamo quindi il modello sul medesimo test set già utilizzato

Si può notare che, come atteso, a livello di performance il modello è leggermente meglio del modello VGG precedentemente creato.
Valutiamo quindi il modello rispetto al tempo necessario per la predizione:

Possiamo notare come il tempo di predizione sia notevolmente minore rispetto a VGG, con un decremento di più di un secondo per immagine. Questo rende il modello molto più generico ed applicabile anche ad applicazioni real time, o quasi.

VGGFace

Come ultima architettura si è deciso di utilizzare un modello preadddestrato su un task di riconoscimento del volto. In questo caso ci si aspetta che le performance siano significativamente migliori rispetto ai due modelli precedenti data la similarità col task originale e dunque con i pesi "bloccati". In particolare si è deciso di utilizzare come architettura VGGFace i cui pesi sono stati scaricati da questo link.

Per lo sviluppo dell'architettura si sono utilizzate le seguenti reference:

Definiamo quindi l'architettura standard della rete scelta e carichiamo i pesi pretrainati. Dal summary si nota come questo modello abbia tantissimi parametri, non ci attendiamo quindi predizioni particolarmente veloci ma piuttosto livelli di accuratezza molto elevati.

Come per i modelli precedenti si blocca l'apprendimento dei pesi dell'architettura base, cosi da non aggiornarli nell'apprendimento. Vengono inoltre aggiunti nuovi layer, trainabili, che verranno addestrati per il task d'interesse.
Dopo alcune prove, e considerando anche il fatto che le features estratte dai primi layer sono già specifiche per la face recognition, si è deciso di non introdurre layer di data augmentation.

In totale questo modello è composto da $145.172.929$ parametri di cui solo $170.051$ addestrabili. Rispetto ai precedenti risulta essere un modello molto "grosso" che richiederà anche tanto spazio in memoria.

Visualizzo l'andamento grafico del training

Dall'andamento del grafico possiamo notare come l'apprendimento sia molto più veloce, già dalla seconda epoca viene infatti raggiunta l'accuracy massima.

I risultati sul test set confermano quanto visto sul validation set, con tutte le immagini correttamente classificate.

Valutiamo quindi il modello rispetto al tempo, come anticipato ci attendiamo un tempo medio molto alto per la singola immagine.

Il tempo richiesto, come atteso, è sicuramente molto alto e maggiore dei due modelli precedenti. Questo non permette sicuramente di applicare il modello in real-time, tuttavia le performace ottime raggiunte potrebbero renderlo ideale per altri task specifici.

Test con immagini reali

Proviamo ad eseguire alcune predizioni su immagini reali scattate in diverse occasioni per verificare le performance dei modelli. Le immagini sono state ritagliate per diminuire il peso, alleggerendo cosi il tempo richiesto per il face detector ed i modelli ma anche per tagliare eventuali persone estranee presenti.

MobileNet-V2

Provo ad effettuare le predizioni usando il modello mobilenet-V$2$.

Possiamo notare che correttamente il face detector individua i volti multipli, ove presenti, nelle immagini. Inoltre questo modello sembra funzionare abbastanza bene anche se in alcuni casi abbiamo dei riconoscimenti errati.
Nello specifico possiamo evidenziare che in alcune foto di 'Riccardo' con gli occhiali egli venga scambiato con 'Ginevra', questo può essere atteso in quanto nel training vi erano poche immagini di 'Riccardo' con gli occhiali, mentre tutte le foto di 'Ginevra' erano con gli occhiali.
Inoltre nelle foto con volti ruotati o con luci "strane" si hanno i riconoscimenti più errati.

VGG16

Utilizzo le stesse immagini di prima ma questa volta con il modello VGG$16$.

Possiamo notare come VGG risolva molti dei casi errati precedentemente individuati, in questo caso vi sono infatti molti meno riconoscimenti errati. Soprattutto vengono confusi 'Riccardo' e 'Lorenzo'.

VGGFace

In questo ultimo test applichiamo il modello VGGFace, dal quale ci attendiamo i risultati migliori.

Come atteso questo modello riesce a riconoscere tutti i volti, eccezion fatta per una singola foto in cui 'Riccardo' viene segnalato come 'Ginevra'. Tuttavia richiede un tempo superiore rispetto agli altri modelli.

Considerazioni Finali

In conclusione è possibile osservare che i modelli di fine tuning che utilizzano i pesi di imagenet risultano essere abbastanza validi, anche se con un ambiente (luci, sfondo, colori, ...) diverso mostrano i propri limiti. Questo perchè comunque nel dataset originale imagenet non sono presenti volti. Mentre, com'è lecito attendersi, il fine tuning della rete VGGFace, che contiene pesi pretrainati su un task di riconoscimento del volto, ottiene performance migliori e più robuste rispetto ai cambiamenti.

Le reti proposte si differenziano anche per il tempo richiesto per la singola predizione, rendendo la rete più o meno adatta ad applicazioni mobile e/o real-time. Ad esempio la rete VGGFace pesa nel complesso oltre $500$MB e dunque viene difficile pensare di poterla inserire in un applicazione mobile, mentre per altri task in cui è possibile avvalersi di hardware più potenti risulta essere la soluzione ideale in quanto fornisce previsioni il più possibile accurate.